package com.isp.common.utils;


import com.isp.common.model.enums.SystemCodeEnum;
import com.isp.common.model.exception.APIRuntimeException;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.joda.time.Months;
import org.joda.time.Weeks;
import org.joda.time.Years;
import org.joda.time.format.DateTimeFormat;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;

/**
 * @author Linsy
 * @version 1.0
 * @created 2024/7/21.
 */
public class DateTimeUtils {
    /**
     * 每天开始时间后缀.
     */
    public static final String START_TIME_SUF = "000000";

    /**
     * 每天结束时间后缀.
     */
    public static final String END_TIME_SUF = "235959";

    /**
     * 每天开始时间后缀 带冒号.
     */
    public static final String START_TIME_SUF_WITH_COLON = "00:00:00";

    /**
     * 每天结束时间后缀 带冒号.
     */
    public static final String END_TIME_SUF_WITH_COLON = "23:59:59";

    /**
     * 日期的默认格式.
     */
    public static final String DEFAULT_DATE_FORMAT = "yyyyMMdd";
    public static final Pattern DEFAULT_DATE_FORMAT_PATTERN = Pattern.compile("[1,2]\\d{3}[0,1]\\d[0-3]\\d");

    /**
     * 日期的默认格式的长度.
     */
    public static final int DEFAULT_DATE_LEN = DEFAULT_DATE_FORMAT.length();

    /**
     * 带杠日期的默认格式
     */
    public static final String DEFAULT_DATE_FORMAT_WITH_BAR = "yyyy-MM-dd";
    public static final Pattern DEFAULT_DATE_FORMAT_WITH_BAR_PATTERN = Pattern.compile("[1,2]\\d{3}-[0,1]\\d-[0-3]\\d");

    /**
     * yyyyMMddHHmmss日期格式.
     */
    public static final String DATE_FORMAT_YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
    public static final Pattern DATE_FORMAT_YYYYMMDDHHMMSS_PATTERN = Pattern.compile(
            "[1,2]\\d{3}[0,1]\\d[0-3]\\d[0-2]\\d[0-5]\\d[0-5]\\d");

    /**
     * yyyy-MM-dd HH:mm:ss日期格式.
     */
    public static final String DATE_FORMAT_FULL = "yyyy-MM-dd HH:mm:ss";
    public static final Pattern DATE_FORMAT_FULL_PATTERN = Pattern.compile(
            "[1,2]\\d{3}-[0,1]\\d-[0-3]\\d [0-2]\\d:[0-5]\\d:[0-5]\\d");

    /**
     * MM月dd日时间格式.
     */
    public static final String DATE_FORMAT_MMDD = "MM月dd日";

    /**
     * MM月dd日HH时 时间格式
     */
    public static final String DATE_FORMAT_MMDDHH = "MM月dd日HH时";

    /**
     * MM月dd日HH:MM时间格式.
     */
    public static final String DATE_FORMAT_MMDDHHMM = "MM月dd日HH:mm";

    /**
     * MM-dd HH:MM时间格式
     */
    public static final String DATE_FORMAT_MMDDHHMM_EN = "MM-dd HH:mm";
    public static final Pattern DATE_FORMAT_MMDDHHMM_EN_PATTERN = Pattern.compile(
            "[0,1]\\d-[0-3]\\d [0-2]\\d:[0-5]\\d");
    public static final String TIME = "HH:mm:ss";
    public static final String TIME2 = "HHmmss";
    /**
     * 一天的毫秒值.
     */
    public static final int MILLISECOND_OF_DAY = 1000 * 60 * 60 * 24;

    /**
     * 一小时的毫秒值.
     */
    public static final int MILLISECOND_OF_HOUR = 1000 * 60 * 60;
    /**
     * 一分钟的毫秒值
     */
    public static final int MILLISECOND_OF_MINUTE = 1000 * 60;

    /**
     * 一天的秒值.
     */
    public static final int SECOND_OF_DAY = 60 * 60 * 24;

    /**
     * 秒与毫秒的倍数
     */
    public static final int MILLI = 1000;

    /**
     * 包含横杠的日期字符串格式
     */
    public static final String DATE_FORMAT_WITH_BAR = "yyyy-MM-dd";

    /**
     * 带分钟的时间字符串格式.
     */
    public static final String DATE_FORMAT_WITH_MIN = "yyyy-MM-dd HH:mm";
    public static final Pattern DATE_FORMAT_WITH_MIN_PATTERN = Pattern.compile(
            "[1,2]\\d{3}-[0,1]\\d-[0-3]\\d [0-2]\\d:[0-5]\\d");

    /**
     * yyyy-MM-dd格式日期正则表达式
     */
    public static final String YYYY_MM_DD_REGEX = "(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|"
            + "[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|"
            + "(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29)";

    /**
     * yyyyMMdd格式日期正则表达式
     */
    public static final String YYYYMMDD_REGEX = "(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|"
            + "[1-9][0-9]{3})(((0[13578]|1[02])(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)(0[1-9]|[12][0-9]|30))|"
            + "(02(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))0229)";

    public static final Pattern YYYMMDD_REGEX_PATTERN = Pattern.compile(YYYYMMDD_REGEX);

    /**
     * yyyyMMddHHmmss格式日期正则表达式
     */
    public static final String YYYYMMDDHHMMSS_REGEX = "((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|"
            + "[1-9][0-9]{3})(((0[13578]|1[02])(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)(0[1-9]|[12][0-9]|30))|"
            + "(02(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))0229))(([01][0-9])|(2[0-3]))([0-5][0-9])([0-5][0-9])";

    /**
     * 将字符串转换为时间格式,时间格式使用yyyyMMdd.
     *
     * @param dateStr 时间字符串
     * @return 转换后的时间
     */
    public static Date stringToTimestamp(String dateStr) {
        return stringToTimestamp(dateStr, DEFAULT_DATE_FORMAT);
    }

    /**
     * 将字符串转换为时间格式.
     *
     * @param dateStr    时间字符串
     * @param dateFormat 时间格式字符串
     * @return 转换后的时间
     */
    public static Date stringToTimestamp(String dateStr, String dateFormat) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
            sdf.setLenient(false);
            return null == dateStr ? null : new Date(sdf.parse(dateStr).getTime());
        } catch (ParseException e) {
            throw new APIRuntimeException(SystemCodeEnum.PARAM_ERROR, "时间格式错误");
        }
    }

    /**
     * 获取当前日期字符串.
     *
     * @return 当前日期字符串
     */
    public static String getTodayStr() {
        return getCurrentTimeStr(DEFAULT_DATE_FORMAT);
    }

    /**
     * 获取当前时间字符串.
     *
     * @param dateFormat 时间格式
     * @return 当前时间字符串
     */
    public static String getCurrentTimeStr(String dateFormat) {
        return new SimpleDateFormat(dateFormat).format(new Date());
    }

    /**
     * 获取前一天日期字符串(格式为yyyyMMdd).
     *
     * @return 前一天日期字符串
     */
    public static String getLastDayStr() {
        return format(yesterday(), DEFAULT_DATE_FORMAT);
    }

    /**
     * 将Date类型的时间转换为字符串类型.
     *
     * @param time 待转换的时间
     * @return 转换后的时间字符串
     */
    public static String timestampToStr(Date time) {
        return timestampToStr(time, DEFAULT_DATE_FORMAT);
    }

    /**
     * 将Date类型的时间转换为字符串类型.(精确到小时)
     *
     * @param time 待转换的时间
     * @return 转换后的时间字符串
     */
    public static String timestampTohourStr(Date time) {
        return timestampToStr(time, DATE_FORMAT_YYYYMMDDHHMMSS);
    }

    /**
     * 将Date类型的时间转换为字符串类型.
     *
     * @param time       待转换的时间
     * @param dateFormat 时间格式
     * @return 转换后的时间字符串
     */
    public static String timestampToStr(Date time, String dateFormat) {
        return dateToStr(time, dateFormat);
    }

    /**
     * 将Date类型的时间转换为字符串类型.
     *
     * @param date 待转换的时间
     * @return 转换后的时间字符串
     */
    public static String dateToStr(Date date) {
        return dateToStr(date, DEFAULT_DATE_FORMAT);
    }

    /**
     * 将Date类型的时间转换为字符串类型.
     *
     * @param date       待转换的时间
     * @param dateFormat 时间格式
     * @return 转换后的时间字符串
     */
    public static String dateToStr(Date date, String dateFormat) {
        return null == date ? null : format(date, dateFormat);
    }

    /**
     * 获取两个时间的时间间隔(单位为为天).
     * 说明:跨天则按天计算.
     *
     * @param start 开始时间
     * @param end   结束时间
     * @return 时间间隔天数
     */
    public static int getIntervalOfDay(Date start, Date end) {
        return (int) daysBetween(start, end);
    }

    /**
     * 两个时间是否是在同一天
     *
     * @param date1
     * @param date2
     * @return
     */
    public static boolean isSameDay(Date date1, Date date2) {
        return isEqualsDate(date1, date2);
    }

    /**
     * 获取两个时间的时间间隔(单位为为天).
     * 说明:计算时如果不足一天,不足部分舍去.
     *
     * @param start      开始时间
     * @param end        结束时间
     * @param dateFormat 时间格式
     * @return 时间间隔天数
     * @throw ParseException    时间转换错误
     */
    public static int getIntervalOfDay(String start, String end, String dateFormat) throws ParseException {

        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        try {

            Calendar startCalendar = Calendar.getInstance();
            Calendar endCalendar = Calendar.getInstance();
            startCalendar.setTime(sdf.parse(start));
            endCalendar.setTime(sdf.parse(end));

            startCalendar.set(Calendar.HOUR_OF_DAY, 0);
            startCalendar.set(Calendar.MINUTE, 0);
            startCalendar.set(Calendar.SECOND, 0);
            startCalendar.set(Calendar.MILLISECOND, 0);

            endCalendar.set(Calendar.HOUR_OF_DAY, 0);
            endCalendar.set(Calendar.MINUTE, 0);
            endCalendar.set(Calendar.SECOND, 0);
            endCalendar.set(Calendar.MILLISECOND, 0);

            return ((int) (endCalendar.getTime().getTime() / MILLI) - (int) (startCalendar.getTime().getTime() / MILLI))
                    / SECOND_OF_DAY;

        } catch (ParseException e) {
            throw e;
        }
    }

    /**
     * 获取两个时间的时间间隔(单位为为天).
     * 说明:计算时如果不足一天,不足部分舍去.
     *
     * @param start 开始时间
     * @param end   结束时间
     * @return 时间间隔天数
     * @throw ParseException    时间转换错误
     */
    public static int getIntervalOfDay(String start, String end) throws ParseException {
        return getIntervalOfDay(start, end, DEFAULT_DATE_FORMAT);
    }

    /**
     * 获取两个时间的时间间隔(单位为为小时).
     * 说明:计算时如果不足一小时时,采用上取整方式.
     *
     * @param start      开始时间
     * @param end        结束时间
     * @param dateFormat 时间格式
     * @return 时间间隔小时
     * @throw ParseException    时间转换错误
     */
    public static int getIntervalOfHour(String start, String end, String dateFormat) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        Date startDate = sdf.parse(start);
        Date endDate = sdf.parse(end);
        return getIntervalOfMinute(startDate, endDate);
    }

    /**
     * 获取两个时间的时间间隔(单位为为小时).
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static int getIntervalOfHour(Date startDate, Date endDate) {
        return (int) Math.ceil(
                Math.abs((float) (endDate.getTime() - startDate.getTime()) / (float) MILLISECOND_OF_HOUR));
    }

    /**
     * 获取两个时间的时间间隔（单位为分）
     *
     * @param start      开始时间
     * @param end        结束时间
     * @param dateFormat 时间格式
     * @return 时间间隔分钟
     * @throws ParseException 时间转换错误
     */
    public static int getIntervalOfMinute(String start, String end, String dateFormat) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        Date startDate = sdf.parse(start);
        Date endDate = sdf.parse(end);

        return getIntervalOfMinute(startDate, endDate);
    }

    public static int getIntervalOfMinute(Date startDate, Date endDate) {
        return (int) Math.ceil(
                Math.abs((float) (endDate.getTime() - startDate.getTime()) / (float) MILLISECOND_OF_MINUTE));
    }

    /**
     * 获取昨天的日期(时分秒为0).
     *
     * @return 昨天的日期
     * @throws ParseException 获取失败抛出异常
     */
    public static Date getLastDayTimestamp() throws ParseException {
        return stringToTimestamp(getLastDayStr());
    }

    /**
     * 验证是否为日期格式.
     *
     * @param dateStr 日期字符串
     * @return 验证结果
     */
    public static boolean isDateTime(String dateStr) {
        return isDateTime(dateStr, YYYMMDD_REGEX_PATTERN);
    }

    public static boolean isDateTime(String dateStr, Pattern pattern) {
        if (StringUtils.isEmpty(dateStr) || pattern == null) {
            return false;
        }

        return pattern.matcher(dateStr).matches();
    }

    /**
     * 验证是否为日期格式.
     *
     * @param dateStr   日期字符串
     * @param dateRegex 日期正则
     * @return 验证结果
     */
    public static boolean isDateTime(String dateStr, String dateRegex) {
        return isDateTime(dateStr, Pattern.compile(dateRegex));
    }

    /**
     * 判断时间time是否在start与end之间.
     *
     * @param time  待判断的时间
     * @param start 开始时间
     * @param end   结束时间
     * @return 判断结果
     */
    public static boolean between(Date time, Date start, Date end) {
        return (null != time) && start.before(time) && end.after(time);
    }

    /**
     * 判断两个时间是否为同一天
     *
     * @param day        比较时间
     * @param compareDay 待比较时间
     * @return 比较结果
     */
    public static boolean sameDay(Date day, Date compareDay) {
        return isEqualsDate(day, compareDay);
    }

    /**
     * 判断时间是否在今日以前
     *
     * @param time 带判断的时间
     * @return 判断结果
     */
    public static boolean beforeToday(Date time) {
        return isBefore(time, now());
    }

    /**
     * 判断时间是否在今日
     *
     * @param time 带判断的时间
     * @return 判断结果
     */
    public static boolean isToday(Date time) {
        return isEqualsDate(now(), time);
    }

    /**
     * 日期计算
     *
     * @param date   原始日期
     * @param field  单位(Calendar类中的单位)
     * @param amount 改变的值
     * @return 计算后的结果
     */
    public static Date add(Date date, int field, int amount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(field, amount);
        return calendar.getTime();
    }

    /**
     * 获取日期区间, 包含结尾那天
     *
     * @param start 开始时间
     * @param end   结束时间(不包含)
     * @return 开始时间与结束时间之间的日期区间的每个日期
     */
    public static List<Date> getDaySection(Date start, Date end) {
        if (start == null || end == null || start.compareTo(end) > 0) {
            return Collections.emptyList();
        }
        List<Date> result = new ArrayList<Date>();
        Date begin = dateStart(start);
        while (!isSameDay(begin, end)) {
            result.add(begin);
            begin = addDays(begin, 1);
        }
        return result;
    }

    /**
     * 获取日期区间, 包含结尾那天
     *
     * @param start 开始时间
     * @param end   结束时间(不包含)
     * @return 开始时间与结束时间之间的日期区间的每个日期
     */
    public static List<Integer> getDaySection(Integer start, Integer end) {
        Date startDate = parseIntDate(start);
        Date endDate = parseIntDate(end);

        List<Date> dateList = getDaySection(startDate, endDate);

        List<Integer> result = new ArrayList<>();
        for (Date date : dateList) {
            result.add(formatDateInt(date));
        }
        return result;
    }

    public static Integer getIntervalOfDay(Integer start, Integer end) {
        if (start == null || end == null || start.equals(end)) {
            return 0;
        }
        if (start.compareTo(end) > 0) {
            Integer tmp = start;
            start = end;
            end = tmp;
        }
        Date startDate = parseIntDate(start);
        Date endDate = parseIntDate(end);
        if (startDate == null || endDate == null) {
            return 0;
        }

        return (int) daysBetween(startDate, endDate);
    }

    public static Integer getIntToday() {
        return formatDateInt(now());
    }

    public static Integer getFutureIntDate(Date startDate, Integer next) {
        Date date = addDays(startDate, next);
        return formatDateInt(date);
    }

    /**
     * 时间类型转换(缺省)
     *
     * @param <T>         目标类型
     * @param <S>         来源类型
     * @param source      来源时间
     * @param targetClass 目标时间类型名
     * @return 转换后的时间
     */
    public static <T, S> T convertDate(S source, Class<T> targetClass) {
        return convertDate(source, targetClass, DEFAULT_DATE_FORMAT);
    }

    /**
     * 时间类型转换
     *
     * @param <T>           目标类型
     * @param <S>           来源类型
     * @param source        来源时间
     * @param targetClass   目标时间类型名
     * @param targetPattern 目标时间的格式
     * @return 转换后的时间
     */
    public static <T, S> T convertDate(S source, Class<T> targetClass, String targetPattern) {
        if (source.getClass().equals(targetClass)) {
            return (T) source;
        }
        Date temp;
        SimpleDateFormat rFormat;
        SimpleDateFormat tFormat = new SimpleDateFormat(targetPattern);
        try {
            if (source instanceof Date) {
                temp = (Date) source;
            } else if (source instanceof String) {
                String dateStr = source.toString();
                if (DEFAULT_DATE_FORMAT_PATTERN.matcher(dateStr).matches()) {
                    rFormat = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
                } else if (DEFAULT_DATE_FORMAT_WITH_BAR_PATTERN.matcher(dateStr).matches()) {
                    rFormat = new SimpleDateFormat(DEFAULT_DATE_FORMAT_WITH_BAR);
                } else if (DATE_FORMAT_YYYYMMDDHHMMSS_PATTERN.matcher(dateStr).matches()) {
                    rFormat = new SimpleDateFormat(DATE_FORMAT_YYYYMMDDHHMMSS);
                } else if (DATE_FORMAT_FULL_PATTERN.matcher(dateStr).matches()) {
                    rFormat = new SimpleDateFormat(DATE_FORMAT_FULL);
                } else if (DATE_FORMAT_MMDDHHMM_EN_PATTERN.matcher(dateStr).matches()) {
                    rFormat = new SimpleDateFormat(DATE_FORMAT_MMDDHHMM_EN);
                } else if (DATE_FORMAT_WITH_MIN_PATTERN.matcher(dateStr).matches()) {
                    rFormat = new SimpleDateFormat(DATE_FORMAT_WITH_MIN);
                } else {
                    return null;
                }
                temp = rFormat.parse(source.toString());
            } else if (source instanceof Integer) {
                temp = parseDate2(source.toString());
            } else if (source instanceof Long) {
                temp = new Date((Long) source);
            } else if (source instanceof DateTime) {
                temp = ((DateTime) source).toDate();
            } else {
                return null;
            }

            if (targetClass.equals(Date.class)) {
                return (T) temp;
            } else if (targetClass.equals(String.class)) {
                return (T) tFormat.format(temp);
            } else if (targetClass.equals(Integer.class)) {
                return (T) Integer.valueOf(Integer.parseInt(tFormat.format(temp)));
            } else if (targetClass.equals(Long.class)) {
                return (T) Long.valueOf(temp.getTime());
            } else if (targetClass.equals(DateTime.class)) {
                return (T) new DateTime(temp.getTime());
            } else {
                return null;
            }
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取时间对应的Calendar域
     *
     * @param date  时间
     * @param field Calendar域
     * @return 值
     */
    public static int getField(Date date, int field) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(field);
    }

    public static int getField(Integer date, int field) {
        return getField(DateTimeUtils.convertDate(date, Date.class), field);
    }

    public static long nowMillis() {
        return System.currentTimeMillis();
    }

    public static Date now() {
        return nowDateTime().toDate();
    }

    public static DateTime nowDateTime() {
        return DateTime.now();
    }

    @Deprecated
    public static Date yestoday() {
        return nowDateTime().plusDays(-1).toDate();
    }

    public static Date yesterday() {
        return nowDateTime().plusDays(-1).toDate();
    }

    public static Date tomorrow() {
        return nowDateTime().plusDays(1).toDate();
    }

    public static DateTime toDateTime(Date date) {
        return new DateTime(date.getTime());
    }

    public static Date dateStart(Date date) {
        return toDateTime(date).withTime(0, 0, 0, 0).toDate();
    }

    public static Date dateEnd(Date date) {
        return toDateTime(date).withTime(23, 59, 59, 0).toDate();
    }

    public static Date todayStart() {
        return nowDateTime().withTime(0, 0, 0, 0).toDate();
    }

    public static Date todayEnd() {
        return nowDateTime().withTime(23, 59, 59, 0).toDate();
    }

    public static Date createWithStart(int year, int month, int day) {
        return nowDateTime().withTimeAtStartOfDay().withDate(year, month, day).toDate();
    }

    public static Date createWithEnd(int year, int month, int day) {
        return nowDateTime().withTime(23, 59, 59, 999).withDate(year, month, day).toDate();
    }

    public static String dateStart(String date) {
        if (StringUtils.isEmpty(date)) {
            return "";
        }
        return date.contains(":") ? date : date + " " + START_TIME_SUF_WITH_COLON;
    }

    public static String dateEnd(String date) {
        if (StringUtils.isEmpty(date)) {
            return "";
        }
        return date.contains(":") ? date : date + " " + END_TIME_SUF_WITH_COLON;
    }

    /////////////////////////////////////////////////////////////////
    // 日期操作

    public static Date addSeconds(Date date, int seconds) {
        return toDateTime(date).plusSeconds(seconds).toDate();
    }

    public static Date addMinutes(Date date, int minutes) {
        return toDateTime(date).plusMinutes(minutes).toDate();
    }

    public static Date addHours(Date date, int hours) {
        return toDateTime(date).plusHours(hours).toDate();
    }

    public static Date addDays(Date date, int days) {
        return toDateTime(date).plusDays(days).toDate();
    }

    public static Integer addDays(Integer integerDate, int days) {
        if (days == 0) {
            return integerDate;
        }
        Date date = addDays(parseIntDate(integerDate), days);
        return formatDateInt(date);
    }

    public static Integer addDays(int days) {
        Date date = addDays(now(), days);
        return formatDateInt(date);
    }

    public static Date addWeeks(Date date, int weeks) {
        return toDateTime(date).plusWeeks(weeks).toDate();
    }

    public static Date addMonths(Date date, int months) {
        return toDateTime(date).plusMonths(months).toDate();
    }

    public static Date addYears(Date date, int years) {
        return toDateTime(date).plusYears(years).toDate();
    }

    public static Duration toDuration(Date date1, Date date2) {
        return new Duration(date1.getTime(), date2.getTime());
    }

    public static long millis(Date date1, Date date2) {
        return Math.abs(date1.getTime() - date2.getTime());
    }

    public static int yearsBetween(Date date1, Date date2) {
        int years = Years.yearsBetween(toDateTime(date1), toDateTime(date2)).getYears();
        return Math.abs(years);
    }

    public static int monthsBetween(Date date1, Date date2) {
        int months = Months.monthsBetween(toDateTime(date1), toDateTime(date2)).getMonths();
        return Math.abs(months);
    }

    public static int weeksBetween(Date date1, Date date2) {
        int weeks = Weeks.weeksBetween(toDateTime(date1), toDateTime(date2)).getWeeks();
        return Math.abs(weeks);
    }

    public static long daysBetween(Date date1, Date date2) {
        return Math.abs(toDuration(date1, date2).getStandardDays());
    }

    public static long hoursBetween(Date date1, Date date2) {
        return Math.abs(toDuration(date1, date2).getStandardHours());
    }

    public static long minutesBetween(Date date1, Date date2) {
        return Math.abs(toDuration(date1, date2).getStandardMinutes());
    }

    public static long secondsBetween(Date date1, Date date2) {
        return Math.abs(toDuration(date1, date2).getStandardSeconds());
    }

    /////////////////////////////////////////////////////////////////
    // 日期比较

    public static boolean isAfter(Date date1, Date date2) {
        return compareDateTime(date1, date2) > 0;
    }

    public static boolean isBefore(Date date1, Date date2) {
        return compareDateTime(date1, date2) < 0;
    }

    public static int compareDate(Date date1, Date date2) {
        return dateStart(date1).compareTo(dateStart(date2));
    }

    public static int compareDateTime(Date date1, Date date2) {
        return toDateTime(date1).compareTo(toDateTime(date2));
    }

    public static boolean isLeapYear(Date date) {
        int year = getYear(date);
        return (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0));
    }

    public static boolean isEqualsDate(Date date1, Date date2) {
        if (date1 == null || date2 == null) {
            return false;
        }
        return dateStart(date1).equals(dateStart(date2));
    }

    public static boolean isEqualsDateTime(Date date1, Date date2) {
        if (date1 == null || date2 == null) {
            return false;
        }
        return date1.equals(date2);
    }

    /////////////////////////////////////////////////////////////////
    // 日期转字符串

    public static String format(Date date, String pattern) {
        return toDateTime(date).toString(pattern);
    }

    public static String format(long timeMillis, String pattern) {
        return new DateTime(timeMillis).toString(pattern);
    }

    public static String format(String pattern) {
        if (pattern == null || "".equals(pattern)) {
            pattern = DATE_FORMAT_FULL;
        }
        return nowDateTime().toString(pattern);
    }

    public static String formatDate() {
        return formatDate(now());
    }

    public static String formatDateTime() {
        return formatDateTime(now());
    }

    public static String formatDate2() {
        return formatDate2(now());
    }

    public static String formatDateTime2() {
        return formatDateTime2(now());
    }

    public static String formatTime() {
        return formatTime(now());
    }

    public static String formatTime2() {
        return formatTime2(now());
    }

    public static String formatDate(Date date) {
        return format(date, DEFAULT_DATE_FORMAT_WITH_BAR);
    }

    public static String formatDate(long timeMillis) {
        return format(timeMillis, DEFAULT_DATE_FORMAT_WITH_BAR);
    }

    public static String formatDate2(Date date) {
        return format(date, DEFAULT_DATE_FORMAT);
    }

    public static String formatDate2(long timeMillis) {
        return format(timeMillis, DEFAULT_DATE_FORMAT);
    }

    public static String formatDateTime(Date date) {
        return format(date, DATE_FORMAT_FULL);
    }

    public static String formatDateTime(long timeMillis) {
        return format(timeMillis, DATE_FORMAT_FULL);
    }

    public static String formatDateTime2(Date date) {
        return format(date, DATE_FORMAT_YYYYMMDDHHMMSS);
    }

    public static String formatDateTime2(long timeMillis) {
        return format(timeMillis, DATE_FORMAT_YYYYMMDDHHMMSS);
    }

    public static String formatTime(Date date) {
        return format(date, TIME);
    }

    public static String formatTime2(Date date) {
        return format(date, TIME2);
    }

    public static Integer formatDateInt(Date date) {
        if (date == null) {
            return null;
        }
        return Integer.parseInt(formatDate2(date));
    }

    /////////////////////////////////////////////////////////////////
    // 字符串转日期

    public static Date parse(String date, String pattern) {
        return DateTime.parse(date, DateTimeFormat.forPattern(pattern)).toDate();
    }

    public static Date parseDate(String date) {
        return parse(date, DEFAULT_DATE_FORMAT_WITH_BAR);
    }

    public static Date parseDateTime(String date) {
        return parse(date, DATE_FORMAT_FULL);
    }

    public static Date parseDate2(String date) {
        return parse(date, DEFAULT_DATE_FORMAT);
    }

    public static Date parseDateTime2(String date) {
        return parse(date, DATE_FORMAT_YYYYMMDDHHMMSS);
    }

    public static Date parseIntDate(Integer date) {
        if (date == null) {
            return null;
        }

        return parseDate2(date.toString());
    }

    /////////////////////////////////////////////////////////////////
    // 获取各日期的年、月、日

    public static int getYear(Date date) {
        return toDateTime(date).getYear();
    }

    public static int getYearFromIntDate(Integer intDate) {
        Date date = parseIntDate(intDate);
        return getYear(date);
    }

    public static int getMonth(Date date) {
        return toDateTime(date).getMonthOfYear();
    }

    public static int getDayOfMonth(Date date) {
        return toDateTime(date).getDayOfMonth();
    }

    public static int getDayOfWeek(Date date) {
        return toDateTime(date).getDayOfWeek();
    }

    public static int getDayOfYear(Date date) {
        return toDateTime(date).getDayOfYear();
    }

    public static int getHour(Date date) {
        return toDateTime(date).getHourOfDay();
    }

    public static String getHourMinuteString(Date date) {
        if (date == null) {
            return "";
        }
        //"yyyy-MM-dd HH:mm:ss"
        String fullTimeString = DateTimeUtils.dateToStr(date, DateTimeUtils.DATE_FORMAT_FULL);
        int idx = fullTimeString.indexOf(":");
        //注意分钟也要一起返回，否则不准
        return fullTimeString.substring(idx - 2, idx + 3);
    }

    public static int getMinute(Date date) {
        return toDateTime(date).getMinuteOfHour();
    }

    public static int getSecond(Date date) {
        return toDateTime(date).getSecondOfMinute();
    }

    ///////////////////////////////////////////////////////////////
    // 获取该月的第一天
    public static Date getFirstDayOfMonth(Date date) {
        return toDateTime(date).dayOfMonth().setCopy(1).toDate();
    }

    // 获取该月的最后一天
    public static Date getLastDayOfMonth(Date date) {
        return toDateTime(date).dayOfMonth().withMaximumValue().toDate();
    }

    //获取本月第一天
    public static Integer getFirstIntDayOfMonth() {
        return formatDateInt(getFirstDayOfMonth(now()));
    }

    // 获取该月的第一天
    public static Integer getFirstIntDayOfMonth(Integer intDate) {
        Date date = getFirstDayOfMonth(parseIntDate(intDate));
        return formatDateInt(getFirstDayOfMonth(date));
    }

    //获取next个月后的当月最后一天
    public static Integer getFutureFinalIntDayOfMonth(int next) {
        Date date = addMonths(now(), next);
        Date result = getLastDayOfMonth(date);
        return formatDateInt(result);
    }

    //获取[dateBegin, dateEnd]的日期列表
    public static List<Integer> getBetweenIntDateList(Integer dateBegin, Integer dateEnd, boolean containBegin,
                                                      boolean containEnd) {
        AssertUtils.isTrue(dateBegin <= dateEnd, SystemCodeEnum.PARAM_ERROR, "起始日期必须小于终止日期");
        int days = getIntervalOfDay(dateBegin, dateEnd);
        if (days == 0) {
            return containBegin && containEnd ?
                    new ArrayList<>(Collections.singleton(dateBegin)) :
                    Collections.emptyList();
        }
        List<Integer> dateList = new ArrayList<>(days);
        int i = 0;
        if (!containBegin) {
            i = 1;
        }
        for (; i < days; i++) {
            dateList.add(addDays(dateBegin, i));
        }
        if (containEnd) {
            dateList.add(dateEnd);
        }
        return dateList;
    }

    /**
     * 获取某个区间、某些星期的日期列表
     *
     * @param dateBegin
     * @param dateEnd
     * @param containBegin 是否包含dateBegin
     * @param containEnd   是否包含dateEnd
     * @param dayOfWeeks   星期列表，返回的日期必须属于该星期列表
     * @return
     */
    public static List<Integer> getBetweenIntDateList(Integer dateBegin, Integer dateEnd, boolean containBegin,
                                                      boolean containEnd, List<Integer> dayOfWeeks) {
        AssertUtils.isTrue(dateBegin <= dateEnd, SystemCodeEnum.PARAM_ERROR, "起始日期必须小于终止日期");
        AssertUtils.notNull(dayOfWeeks, SystemCodeEnum.PARAM_ERROR, "星期列表不能为空");
        int days = getIntervalOfDay(dateBegin, dateEnd);
        if (days == 0) {//起止日期相等
            if (!containBegin || !containEnd) {
                return Collections.emptyList();
            }
            Integer dayOfWeek = DateTimeUtils.getField(dateBegin, Calendar.DAY_OF_WEEK);
            return dayOfWeeks.contains(dayOfWeek) ?
                    new ArrayList<>(Collections.singleton(dateBegin)) :
                    Collections.emptyList();
        }
        List<Integer> dateList = new ArrayList<>(days);
        int i = 0;
        if (!containBegin) {
            i = 1;
        }
        Date dateBeginDate = convertDate(dateBegin, Date.class);
        for (; i < days; i++) {
            Date curDate = addDays(dateBeginDate, i);
            Integer dayOfWeek = DateTimeUtils.getField(curDate, Calendar.DAY_OF_WEEK);
            if (dayOfWeeks.contains(dayOfWeek)) {
                dateList.add(convertDate(curDate, Integer.class));
            }
        }
        if (containEnd) {
            Integer dayOfWeek = DateTimeUtils.getField(dateEnd, Calendar.DAY_OF_WEEK);
            if (dayOfWeeks.contains(dayOfWeek)) {
                dateList.add(dateEnd);
            }
        }
        return dateList;
    }

    /**
     * 获取指定日期的开始时间
     *
     * @param today 指定日期
     * @return 开始时间
     */
    public static Date getDayStartTime(Date today) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(today);

        // 获取指定的开始时间
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }

    /**
     * 获取指定日期的开始时间
     *
     * @param today 指定日期
     * @return 开始时间
     */
    public static Date getDayEndTime(Date today) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(today);

        // 获取指定的截止时间
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar.getTime();
    }
}
